package com.you.weixinpay.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.you.weixinpay.domain.entity.TOrderInfo;
import com.you.weixinpay.domain.entity.TRefundInfo;
import com.you.weixinpay.enums.OrderStatus;
import com.you.weixinpay.enums.PaymentType;
import com.you.weixinpay.service.TOrderInfoService;
import com.you.weixinpay.service.TRefundInfoService;
import com.you.weixinpay.service.WxPayService;
import com.you.weixinpay.utils.WeChatNativePayUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

@Service
@Slf4j
public class WxPayServiceImpl implements WxPayService {

    @Autowired
    private WeChatNativePayUtil weChatNativePayUtil;
    @Autowired
    private TOrderInfoService orderInfoService;
    @Resource
    private TRefundInfoService refundInfoService;
    private final ReentrantLock lock = new ReentrantLock();
    @Override
    public Map<String, Object> nativePay(Long productId) throws Exception {
        log.info("开始生成Native支付二维码");

        // 1. 生成订单
        // 这里应该获取当前登录用户ID，假设为1
        Long userId = 1L;
        TOrderInfo order = orderInfoService.createOrderByProductId(productId, PaymentType.WXPAY.getType(), userId);
        String codeUrl = order.getCodeUrl();
        String orderNo = order.getOrderNo();
        if (!ObjectUtils.isEmpty(codeUrl)) {
            log.info("订单已存在，二维码已保存");
            Map<String, Object> map = new HashMap<>();
            map.put("codeUrl", codeUrl);
            map.put("orderNo", orderNo);
            return map;
        }

        BigDecimal totalFee = order.getTotalFee();
        // 2. 调用微信Native支付接口
        JSONObject result = weChatNativePayUtil.createOrder(orderNo, totalFee, order.getTitle());

        // 3. 处理返回结果
        log.info("微信Native支付返回结果: {}", result);

        // 4. 保存二维码链接到数据库
        codeUrl = result.getString("code_url");
        order.setCodeUrl(codeUrl);
        orderInfoService.updateById(order);

        // 5. 返回结果
        Map<String, Object> map = new HashMap<>();
        map.put("codeUrl", codeUrl);
        map.put("orderNo", orderNo);

        return map;
    }

    @Override
    public void processOrder(String outTradeNo) {
        log.info("处理订单回调更新状态【核心】");

        /*在对业务数据进行状态检查和处理之前，
        要采用数据锁进行并发控制，
        以避免函数重入造成的数据混乱*/

        //尝试获取锁：
        // 成功获取则立即返回true，获取失败则立即返回false。不必一直等待锁的释放
        if(lock.tryLock()){
            try {
                log.info("获取锁成功，处理订单回调更新状态");
                //处理重复的通知
                //接口调用的幂等性：无论接口被调用多少次，产生的结果是一致的。
                // 获取订单状态
                String orderStatus = orderInfoService.getOrderStatus(outTradeNo);
                // 如果订单状态是已支付，则返回
                if (!OrderStatus.NOTPAY.getType().equals(orderStatus)) {
                    return;
                }

                //模拟通知并发
                try {
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                //处理订单回调更新状态
                orderInfoService.updateStatusByOrderNo(outTradeNo,OrderStatus.SUCCESS.getType());
                log.info("更新订单状态成功，订单号：{}", outTradeNo);
            } finally {
                // 必须主动释放锁
                lock.unlock();
            }
        }

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void refund(String orderNo, String reason) throws Exception {
        log.info("创建退款单记录");

        // 1. 查询订单
        TOrderInfo order = orderInfoService.getOne(new LambdaQueryWrapper<TOrderInfo>()
                .eq(TOrderInfo::getOrderNo, orderNo));
        if (order == null) {
            throw new RuntimeException("订单不存在");
        }

        // 2. 检查订单状态是否可退款
        if (!OrderStatus.SUCCESS.getType().equals(order.getOrderStatus())) {
            throw new RuntimeException("订单状态不允许退款");
        }

        // 3. 创建退款记录
        TRefundInfo refundInfo = refundInfoService.createRefundByOrderNo(orderNo, reason);

        // 4. 调用微信退款API
        JSONObject result = weChatNativePayUtil.refund(
                orderNo,
                refundInfo.getRefundNo(),
                order.getTotalFee(),
                order.getTotalFee(), // 这里假设全额退款，可根据业务调整
                reason
        );

        // 5. 更新退款记录
        refundInfo.setRefundId(result.getString("refund_id"));
        refundInfo.setContentNotify(result.toJSONString());
        refundInfoService.updateById(refundInfo);

        log.info("退款申请成功，退款单号：{}", refundInfo.getRefundNo());
    }

    @Override
    public void processRefund(String refundNo, String refundStatus) {
        log.info("处理退款结果，退款单号：{}，状态：{}", refundNo, refundStatus);

        // 1. 查询退款记录
        TRefundInfo refundInfo = refundInfoService.getOne(new LambdaQueryWrapper<TRefundInfo>()
                .eq(TRefundInfo::getRefundNo, refundNo));
        if (refundInfo == null) {
            log.error("退款记录不存在，退款单号：{}", refundNo);
            throw new RuntimeException("退款记录不存在");
        }

        // 2. 更新退款状态
        refundInfo.setRefundStatus(refundStatus);
        refundInfoService.updateById(refundInfo);

        // 3. 如果是全额退款，更新订单状态
        if ("SUCCESS".equals(refundStatus)) {
            TOrderInfo order = orderInfoService.getOne(new LambdaQueryWrapper<TOrderInfo>()
                    .eq(TOrderInfo::getOrderNo, refundInfo.getOrderNo()));
            if (order != null) {
                order.setOrderStatus(OrderStatus.REFUND_SUCCESS.getType());
                orderInfoService.updateById(order);
            }
        }

        log.info("退款处理完成，退款单号：{}", refundNo);
    }

    @Override
    public void cancelOrder(String orderNo) {
        // 1. 查询订单状态
        TOrderInfo order = orderInfoService.getOne(new LambdaQueryWrapper<TOrderInfo>()
                .eq(TOrderInfo::getOrderNo, orderNo));
        if (order == null) {
            throw new RuntimeException("订单不存在");
        }

        // 2. 检查订单状态是否可以取消
        if (!OrderStatus.NOTPAY.getType().equals(order.getOrderStatus())) {
            throw new RuntimeException("当前订单状态不允许取消");
        }

        // 3. 调用微信支付关单接口
        try {
            weChatNativePayUtil.closeOrder(orderNo);
        } catch (Exception e) {
            log.error("微信关单接口调用失败", e);
            throw new RuntimeException("微信关单失败");
        }

        // 4. 更新本地订单状态为已取消
        order.setOrderStatus(OrderStatus.CANCEL.getType());
        orderInfoService.updateById(order);

        log.info("订单取消成功，订单号：{}", orderNo);
    }

    @Override
    public String queryOrder(String orderNo) throws Exception {
        log.info("查询订单状态，订单号：{}", orderNo);

        // 1. 查询本地订单
        TOrderInfo order = orderInfoService.getOne(new LambdaQueryWrapper<TOrderInfo>()
                .eq(TOrderInfo::getOrderNo, orderNo));
        if (order == null) {
            throw new RuntimeException("订单不存在");
        }

        // 2. 调用微信支付查询接口,返回订单状态
        return weChatNativePayUtil.queryOrder(orderNo);
    }

    @Override
    public String queryRefund(String refundNo) throws Exception {
        return weChatNativePayUtil.queryRefund(refundNo);
    }
}
